FreeRTOS 协同程序

协同程序是一种特殊的多任务编程方式,多个协同程序之间共用调用栈,且正在运行的协同程序不会被其他协程抢占(可以被任务和中断抢占),正在运行的协同程序只能自己主动让出CPU的使用权。要使用协同程序,需要将FreeRTOSConfig.h中的configUSE_CO_ROUTINES设为1

FreeRTOS的协同程序采用switch-case实现,函数定义方式如下:

1void CoRoutineTask(CoRoutineHandle_t handle,UBaseType_t uxIndex)
2{
3    //协同程序中变量如果要保证值在下一次运行时仍有效,则必须为static
4    static const TickType_t delay = 1000 / portTICK_PERIOD_MS;
5 
6    //协同程序必须以crSTART(handle)开始
7    crSTART(handle);
8     
9    //协同程序主体
10    while(1)
11    {
12        /* 协同程序工作内容 */
13         
14        //主动阻塞1000ms,让出CPU使用权
15        crDELAY(handle,delay);
16    }
17     
18    //协同程序必须以crEND()结束
19    crEND()    
20}

使用vCoRoutineSchedule来调度协同程序,调用这个函数时,他会运行可运行的优先级最高的协同程序,当这个协同程序让出CPU时,vCoRoutineSchedule返回。需要不断的调用这个函数来进行协程的调度。

1#include <croutine.h>
2void vCoRoutineSchedule(void);

使用xCoRoutineCreate来创建一个协程,它的第一个参数是协程函数,第二个参数是协程优先级,可以用同一个协程函数创建多个协程,第三个参数用来区分同一个函数创建的协程。

1#include <croutine.h>
2BaseType_t xCoRoutineCreate(crCOROUTINE_CODE pxCoRoutineCode, 
3                            UBaseType_t uxPriority, 
4                            UBaseType_t uxIndex );

下面这个示例使用同一个函数创建了4个协程,协程函数打印uxIndex并阻塞1000ms:

1#include <stm32f4xx.h>
2#include <FreeRTOS.h>
3#include <task.h>
4#include <croutine.h>
5#include <uart.h>
6 
7void coTask(CoRoutineHandle_t h,UBaseType_t uxIndex);
8void task(void* args);
9 
10int main()
11{
12    //配置USART1
13    USART1_Config();
14    //创建协程
15    xCoRoutineCreate(coTask,0,0);
16    xCoRoutineCreate(coTask,0,1);
17    xCoRoutineCreate(coTask,0,2);
18    xCoRoutineCreate(coTask,0,3);
19    //创建任务,用于调度协程
20    xTaskCreate(task,"task1",configMINIMAL_STACK_SIZE,NULL,1,NULL);
21    //启动任务调度器
22    vTaskStartScheduler();
23}
24 
25void task(void* args)
26{
27    while(1)
28    {
29        //运行优先级最高的协程,该协程让出时,函数返回
30        vCoRoutineSchedule();
31    }
32}
33 
34 
35void coTask(CoRoutineHandle_t handle,UBaseType_t uxIndex)
36{
37    //如果协程函数希望在阻塞后仍能保存变量的值,那么变量必须是static的
38    static const TickType_t delay = 1000 / portTICK_PERIOD_MS;
39     
40    //协程函数必须以crSTART开始
41    crSTART(handle);
42     
43    while(1)
44    {
45        //通过串口打印uxIndex
46        USART_printf(USART1,"coTask1 : %d\n",uxIndex);
47        //在协程中延时1000ms
48        crDELAY(handle,delay);
49    }
50     
51    //协程函数必须以crEND结束
52    crEND();
53     
54}

Image